package com.example.videodemo;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by dingfeng on 2016/7/14.
 */
public class VideoView extends SurfaceView {

    private static final String TAG = "dingfeng";

    private Context mContext;
    private Uri mUri;  // 多媒体文件uri
    private int mDuration; // 多媒体时长

    // Media state
    private static final int STATE_ERROR = -1;
    private static final int STATE_IDLE = 0;
    private static final int STATE_PREPARING = 1;
    private static final int STATE_PREPARED = 2;
    private static final int STATE_PLAYING = 3;
    private static final int STATE_PAUSED = 4;
    private static final int STATE_PLAYBACK_COMPLETED = 5;
    private static final int STATE_RESUME = 6;

    private int mCurrentState = STATE_IDLE;

    private int mVideoWidth; // 视频宽
    private int mVideoHeight; // 视频高

    private int mSurfaceWidth; // Surface宽
    private int mSurfaceHeight; // Surface高

    private SurfaceHolder mSurfaceHolder;
    private MediaPlayer mMediaPlayer;

    private int mCurrentBufferPercentage;
    private int mSeekWhenPrepared;

    // listener
    private MediaPlayer.OnCompletionListener mOnCompletionListener;
    private MediaPlayer.OnPreparedListener mOnPreparedListener;
    private MediaPlayer.OnErrorListener mOnErrorListener;
    private MediaPlayer.OnSeekCompleteListener mOnSeekCompleteListener;
    private MediaPlayer.OnInfoListener mOnInfoListener;
    private MediaPlayer.OnBufferingUpdateListener mOnBufferingUpdateListener;


    private List<VideoInfo> mVideoList = new ArrayList<>();

    public VideoView(Context context) {
        super(context);
        initVideoView(context);
    }

    public VideoView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public VideoView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initVideoView(context);
    }

    // init video view
    private void initVideoView(Context context) {
        mContext = context;
        mVideoWidth = 0;
        mVideoHeight = 0;
        getHolder().addCallback(mSurfaceHolderCallback);// add surface holder callback
        setFocusable(true);
        setFocusableInTouchMode(true);
        requestFocus();
        mCurrentState = STATE_IDLE;
        if (context instanceof Activity) {
            ((Activity) context).setVolumeControlStream(AudioManager.STREAM_MUSIC); //Volume stream
        }
    }

    public void setVideoLayout() {
        setVideoLayout(0, 0);
    }

    public void setVideoLayout(int parentWidth, int parentHeight) {
        // window size
//        DisplayMetrics disp = mContext.getResources().getDisplayMetrics();
//        int windowWidth = disp.widthPixels;
//        int windowHeight = disp.heightPixels;
//        Log.d(TAG, "windowWidth:" + windowWidth + "   windowHeight:" + windowHeight);

        // get surface view with and height
        if (parentWidth == 0 || parentHeight == 0) {
            mSurfaceWidth = getWidth();
            mSurfaceHeight = getHeight();
        } else {
            mSurfaceWidth = parentWidth;
            mSurfaceHeight = parentHeight;
        }

        float aspectRatio = (float) mVideoWidth / mVideoHeight;
//        Log.d(TAG, "mVideoWidth:" + mVideoWidth + "   mVideoHeight:" + mVideoHeight + "  aspectRatio:" + aspectRatio);
//        Log.d(TAG, "mSurfaceWidth:" + mSurfaceWidth + "   mSurfaceHeight:" + mSurfaceHeight);
        int videoWidth;
        int videoHeight;
        if (aspectRatio < 1) {
            videoHeight = mSurfaceHeight;
            videoWidth = (int) (videoHeight * aspectRatio);
        } else {
            videoHeight = mSurfaceHeight;
            videoWidth = mSurfaceWidth;
        }

        // set new surface view width and height
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        layoutParams.width = videoWidth;
        layoutParams.height = videoHeight;
        setLayoutParams(layoutParams);

        getHolder().setFixedSize(videoWidth, videoHeight);
    }

    // 设置文件路径
    public void setVideoPath(String path) {
        setVideoURI(Uri.parse(path));
    }

    // 设置文件Uri
    public void setVideoURI(Uri uri) {
        mUri = uri;
        mSeekWhenPrepared = 0;
        openVideo();
        requestLayout();
        invalidate();
    }

    public void openVideo() {
        if (mUri == null || mSurfaceHolder == null) {
            Log.d(TAG, "Open video failed.");
            return;
        }

        release();

        try {
            mDuration = -1;
            mCurrentBufferPercentage = 0;
            mMediaPlayer = new MediaPlayer();
            // 设置监听
            mMediaPlayer.setOnPreparedListener(mPreparedListener);
            mMediaPlayer.setOnVideoSizeChangedListener(mVideoSizeChangedListener);
            mMediaPlayer.setOnCompletionListener(mCompletionListener);
            mMediaPlayer.setOnErrorListener(mErrorListener);
            mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
            mMediaPlayer.setOnInfoListener(mInfoListener);
            mMediaPlayer.setOnSeekCompleteListener(mSeekCompleteListener);

            mMediaPlayer.setDataSource(mContext, mUri);// 设置播放资源
            mMediaPlayer.setDisplay(mSurfaceHolder);
            mMediaPlayer.setScreenOnWhilePlaying(true);

            mMediaPlayer.prepareAsync();
            mCurrentState = STATE_PREPARING; // 正在准备阶段
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "Unable to open content:" + mUri, e);
            mCurrentState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } catch (SecurityException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "Unable to open content:" + mUri, e);
            mCurrentState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "Unable to open content:" + mUri, e);
            mCurrentState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "Unable to open content:" + mUri, e);
            mCurrentState = STATE_ERROR;
            mErrorListener.onError(mMediaPlayer, MediaPlayer.MEDIA_ERROR_UNKNOWN, 0);
            return;
        }

    }

    SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            Log.d(TAG, "surfaceCreated..." + mCurrentState);

            mSurfaceHolder = holder;
//            openVideo();

            if (mMediaPlayer != null && mCurrentState == STATE_PAUSED) {
                mMediaPlayer.setDisplay(mSurfaceHolder);
                resume();
            } else {
                openVideo();
            }
        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {
            Log.d(TAG, "surfaceDestroyed...");
            mSurfaceHolder = null;
            mSeekWhenPrepared = getCurrentPosition();
//            stop();
            pause();
        }
    };

    /**********************************************************************************************/

    MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            Log.d(TAG, "onPrepared...");
            mCurrentState = STATE_PREPARED;

            if (mOnPreparedListener != null) {
                mOnPreparedListener.onPrepared(mMediaPlayer);
            }

            // seek
            int seekToPosition = mSeekWhenPrepared;
            if (seekToPosition != 0) {
                seekTo(seekToPosition);
            }

            if (mVideoWidth != 0 && mVideoHeight != 0) {
                start();
            }
        }
    };

    MediaPlayer.OnVideoSizeChangedListener mVideoSizeChangedListener = new MediaPlayer.OnVideoSizeChangedListener() {
        @Override
        public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
            Log.d(TAG, "onVideoSizeChanged:  width=" + width + " height=" + height);
            mVideoWidth = mp.getVideoWidth();
            mVideoHeight = mp.getVideoHeight();
            setVideoLayout();
        }
    };

    MediaPlayer.OnBufferingUpdateListener mBufferingUpdateListener = new MediaPlayer.OnBufferingUpdateListener() {
        @Override
        public void onBufferingUpdate(MediaPlayer mp, int percent) {
            mCurrentBufferPercentage = percent;
            if (mOnBufferingUpdateListener != null) {
                mOnBufferingUpdateListener.onBufferingUpdate(mp, percent);
            }
        }
    };

    MediaPlayer.OnInfoListener mInfoListener = new MediaPlayer.OnInfoListener() {
        @Override
        public boolean onInfo(MediaPlayer mp, int what, int extra) {
            Log.d(TAG, "onInfo...");
            if (mOnInfoListener != null) {
                mOnInfoListener.onInfo(mp, what, extra);
            } else if (mMediaPlayer != null) {
                if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
                    mMediaPlayer.pause();
                } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END) {
                    mMediaPlayer.start();
                }
            }
            return true;
        }
    };

    MediaPlayer.OnSeekCompleteListener mSeekCompleteListener = new MediaPlayer.OnSeekCompleteListener() {
        @Override
        public void onSeekComplete(MediaPlayer mp) {
            Log.d(TAG, "onSeekComplete...");
        }
    };

    MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            Log.d(TAG, "onCompletion...");
            mCurrentState = STATE_PLAYBACK_COMPLETED;
            if (mOnCompletionListener != null) {
                mOnCompletionListener.onCompletion(mp);
            }
        }
    };

    MediaPlayer.OnErrorListener mErrorListener = new MediaPlayer.OnErrorListener() {
        @Override
        public boolean onError(MediaPlayer mp, int what, int extra) {
            Log.d(TAG, "what=" + what + " extra=" + extra);
            mCurrentState = STATE_ERROR;
            if (mOnErrorListener != null) {
                if (mOnErrorListener.onError(mp, what, extra)) {
                    return true;
                }
            }
            if (getWindowToken() != null) {
                int message = what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK ?
                        R.string.videoview_error_text_invalid_progressive_playback :
                        R.string.videoview_error_text_unknown;
                new AlertDialog.Builder(mContext)
                        .setTitle(R.string.videoview_error_title)
                        .setMessage(message)
                        .setPositiveButton(
                                R.string.videoview_error_button,
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int whichButton) {

                                    }
                                }).setCancelable(false).show();
            }

            return true;
        }
    };

    /**********************************************************************************************/

    /**********************************************************************************************/

    public void setVideoList(List<VideoInfo> list) {
        mVideoList = list;
    }

    public int getUrlPosition() {
        for (int i = 0; i < mVideoList.size(); i++) {
            if (mUri.toString().equals(mVideoList.get(i).getPath())) {
                return i;
            }
        }
        return -1;
    }

    public void start() {
        Log.d(TAG, "start..." + isInPlaybackState());
        if (isInPlaybackState()) {
            mMediaPlayer.start();
            mCurrentState = STATE_PLAYING;
        }
    }

    public void pause() {
        if (isInPlaybackState()) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
                mCurrentState = STATE_PAUSED;
            }
        }
    }

//    public void suspend() {
//        if (isInPlaybackState()) {
//            release(false);
//            mCurrentState = STATE_SUSPEND_UNSUPPORTED;
//            Log.d(TAG, "Unable to suspend video. Release MediaPlayer.");
//        }
//    }

    public void resume() {
        openVideo();
    }

    public void stop() {
        if (mMediaPlayer != null) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
        }
    }

    public void release() {
        if (mMediaPlayer != null) {
            mMediaPlayer.reset();
            mMediaPlayer.release();
            mMediaPlayer = null;
            mCurrentState = STATE_IDLE;
        }
    }

    public boolean pre() {
        int currentVideo = getUrlPosition();
        if (currentVideo == 0) {
            return false;
        } else {
            currentVideo--;
        }
        setVideoPath(mVideoList.get(currentVideo).mPath);
        return true;
    }

    public boolean next() {
        int currentVideo = getUrlPosition();
        if (currentVideo == mVideoList.size() - 1) {
            return false;
        } else {
            currentVideo++;
        }
        setVideoPath(mVideoList.get(currentVideo).mPath);
        return true;
    }

    /**********************************************************************************************/

    /**********************************************************************************************/
    public void seekTo(int msec) {
        if (isInPlaybackState()) {
            mMediaPlayer.seekTo(msec);
            mSeekWhenPrepared = 0;
        } else {
            mSeekWhenPrepared = msec;
        }
    }

    public int getDuration() {
        if (isInPlaybackState()) {
            if (mDuration > 0) {
                return mDuration;
            }
            mDuration = mMediaPlayer.getDuration();
            return mDuration;
        }
        mDuration = -1;
        return mDuration;
    }

    public int getCurrentPosition() {
        if (isInPlaybackState()) {
            return mMediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    public int getBufferPercentage() {
        if (mMediaPlayer != null) {
            return mCurrentBufferPercentage;
        }
        return 0;
    }

    public boolean isPlaying() {
        return isInPlaybackState() && mMediaPlayer.isPlaying();
    }

    protected boolean isInPlaybackState() {
        return (mMediaPlayer != null && mCurrentState != STATE_ERROR
                && mCurrentState != STATE_IDLE && mCurrentState != STATE_PREPARING);
    }

    /**********************************************************************************************/

    public void setOnPreparedListener(MediaPlayer.OnPreparedListener l) {
        mOnPreparedListener = l;
    }

    public void setOnCompletionListener(MediaPlayer.OnCompletionListener l) {
        mOnCompletionListener = l;
    }

    public void setOnErrorListener(MediaPlayer.OnErrorListener l) {
        mOnErrorListener = l;
    }

    public void setOnBufferingUpdateListener(MediaPlayer.OnBufferingUpdateListener l) {
        mOnBufferingUpdateListener = l;
    }

    public void setOnSeekCompleteListener(MediaPlayer.OnSeekCompleteListener l) {
        mOnSeekCompleteListener = l;
    }

    public void setOnInfoListener(MediaPlayer.OnInfoListener l) {
        mOnInfoListener = l;
    }

}
